//
// Created by martin on 3/22/22.
//

#include <iostream>
#include <cassert>
#include <type_traits>

using namespace std;

struct Trivial1 { };
struct Trivial2 {
public:
	int a;
private:
	int b;
};

struct Trivial3 {
	Trivial1 a;
	Trivial2 b;
};

struct Trivial4 {
	Trivial2 a[23];
};

struct Trivial5 {
	int x;
	static int y;
};

struct NonTrivial1 {
	NonTrivial1() : z(42) { }
	int z;
};

struct NonTrivial2 {
	NonTrivial2() = default;
	int y;
};

struct NonTrivial3 {
	NonTrivial3();
	int w;
};

NonTrivial3::NonTrivial3() = default;

struct NonTrivial4 {
	Trivial5 c;
	virtual void f();
};

struct B1 {};
struct B2 {};

struct D1 : B1 {
	B1 b;
	int i;
};

struct D2 : B1 {
	B2 b;
	int i;
};


struct SLayout1 { };

struct SLayout2 {
private:
	int x;
	int y;
};

struct SLayout3 : SLayout1 {
	int x;
	int y;
	void f();
};

struct SLayout4 : SLayout1 {
	int x;
	SLayout1 y;
};

struct SLayout5 : /*SLayout1,*/ SLayout3 { };

struct SLayout6 { static int y; };

struct SLayout7 : SLayout6 { int x; };

struct NonSLayout1 : SLayout1 {
	SLayout1 x;
	int i;
};

struct NonSLayout2 : SLayout2 { int z; };

struct NonSLayout3 : NonSLayout2 {};

struct NonSLayout4 {
public:
	int x;
private:
	int y;
};

int main()
{
	cout << is_standard_layout<SLayout1>::value << endl; // 1
	cout << is_standard_layout<SLayout2>::value << endl; // 1
	cout << is_standard_layout<SLayout3>::value << endl; // 1
	cout << is_standard_layout<SLayout4>::value << endl; // 1
	cout << is_standard_layout<SLayout5>::value << endl; // 1
	cout << is_standard_layout<SLayout6>::value << endl; // 1
	cout << is_standard_layout<SLayout7>::value << endl; // 1

	cout << is_standard_layout<NonSLayout1>::value << endl; // 0
	cout << is_standard_layout<NonSLayout2>::value << endl; // 0
	cout << is_standard_layout<NonSLayout3>::value << endl; // 0
	cout << is_standard_layout<NonSLayout4>::value << endl; // 0
	cout << "ok" << endl;
	D1 d1;
	D2 d2;
	cout << hex;
	// 7ffcdf314d00
	cout << reinterpret_cast<long long>(&d1) << endl;
	// 7ffcdf314d01
	cout << reinterpret_cast<long long>(&d1.b) << endl;
	// 7ffcdf314d04
	cout << reinterpret_cast<long long>(&d1.i) << endl;

	// 7ffcdf314d10
	cout << reinterpret_cast<long long>(&d2) << endl;
	// 7ffcdf314d10
	cout << reinterpret_cast<long long>(&d2.b) << endl;
	// 7ffcdf314d14
	cout << reinterpret_cast<long long>(&d2.i) << endl;

	cout << is_trivial<Trivial1>::value << endl;  // 1
	cout << is_trivial<Trivial2>::value << endl;  // 1
	cout << is_trivial<Trivial3>::value << endl;  // 1
	cout << is_trivial<Trivial4>::value << endl;  // 1
	cout << is_trivial<Trivial5>::value << endl;  // 1
	cout << is_trivial<NonTrivial1>::value << endl;  // 0
	cout << is_trivial<NonTrivial2>::value << endl;  // 1
	cout << is_trivial<NonTrivial3>::value << endl;  // 0
	cout << is_trivial<NonTrivial4>::value << endl;  // 0
	return 0;
}
